home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Source Code
/
Libraries
/
PNL Libraries
/
MyCollections.p
< prev
next >
Wrap
Text File
|
1995-10-22
|
22KB
|
865 lines
unit MyCollections;
interface
uses
Types;
const
no_tag = 0;
type
PermuteArray = array[1..8000] of integer;
PermuteArrayPtr = ^PermuteArray;
type
tagType = OSType;
indexType = longint;
collection = object
error: OSErr; { PUBLIC }
safeget: boolean; { PUBLIC }
testheap: boolean; { PUBLIC }
data: handle; { PRIVATE }
size: longint; { PRIVATE }
cnt: indexType; { PRIVATE }
fixed, tagged: boolean; { PRIVATE }
lensize, tagsize: longint; { PRIVATE }
searchindex: indexType; { PRIVATE }
searchtag: tagType; { PRIVATE }
cacheoffset: longint; { PRIVATE }
cachelen: longint; { PRIVATE }
cacheindex: indexType; { PRIVATE }
procedure Create (siz: longint; fix, tag: boolean);
procedure CreateFromHandle (d: handle);
procedure Destroy;
procedure SetDataHandle (d: handle);
function GetDataHandle: handle;
procedure Reset;
function Count: indexType;
function GetTag (index: indexType): tagType;
function GetIndex (tag: tagType): indexType;
procedure SetTag (index: indexType; tag: tagType);
function Exists (index: indexType): boolean;
function ExistsTag (tag: univ tagType): boolean;
function Info (index: indexType; var len: longint): boolean;
function InfoTag (tag: univ tagType; var len: longint): boolean;
procedure Delete (index: indexType);
procedure DeleteTag (tag: univ tagType);
procedure InsertBefore (index: indexType);
procedure Permute (map: PermuteArrayPtr); { WARNING: Destroys permute array data }
procedure AddBoolean (b: boolean);
procedure AddTagBoolean (tag: univ tagType; b: boolean);
procedure AddLong (n: univ longint);
procedure AddTagLong (tag: univ tagType; n: univ longint);
procedure AddString (s: Str255);
procedure AddTagString (tag: univ tagType; s: Str255);
procedure AddData (p: ptr; len: longint);
procedure AddTagData (tag: univ tagType; p: ptr; len: longint);
procedure AddItem (p: ptr);
procedure AddTagItem (tag: univ tagType; p: ptr);
procedure SetBoolean (index: indexType; b: boolean);
procedure SetTagBoolean (tag: univ tagType; b: boolean);
procedure SetLong (index: indexType; n: univ longint);
procedure SetTagLong (tag: univ tagType; n: univ longint);
procedure SetString (index: indexType; s: Str255);
procedure SetTagString (tag: univ tagType; s: Str255);
procedure SetData (index: indexType; p: ptr; len: longint);
procedure SetTagData (tag: univ tagType; p: ptr; len: longint);
procedure SetItem (index: indexType; p: ptr);
procedure SetTagItem (tag: univ tagType; p: ptr);
function GetBoolean (index: indexType): boolean;
function GetTagBoolean (tag: univ tagType): boolean;
procedure GetLong (index: indexType; var l: univ longint);
procedure GetTagLong (tag: univ tagType; var l: univ longint);
function GetString (index: indexType): Str255;
function GetTagString (tag: univ tagType): Str255;
procedure GetData (index: indexType; p: ptr; len: longint);
procedure GetTagData (tag: univ tagType; p: ptr; len: longint);
procedure GetItem (index: indexType; p: ptr);
procedure GetTagItem (tag: univ tagType; p: ptr);
procedure InvalidateCache;
function GetOffset (index: indexType; var offset: longint; var len: longint): boolean; { PRIVATE }
function GetTagOffset (tag: univ tagType; var offset: longint; var len: longint; var index: indexType; test: boolean): boolean; { PRIVATE }
procedure AddChunk (tag: tagType; p: ptr; len: longint); { PRIVATE }
procedure SetChunk (offset, l: longint; tag: tagType; p: ptr; len: longint); { PRIVATE }
procedure SetChunkIndex (index: indexType; p: ptr; len: longint); { PRIVATE }
procedure SetChunkTag (tag: tagType; p: ptr; len: longint); { PRIVATE }
procedure GetChunkIndex (index: indexType; len: longint; p: ptr); { PRIVATE }
procedure GetChunkTag (tag: tagType; len: longint; p: ptr); { PRIVATE }
end;
procedure HackUpdateHandleToCollection (data: handle);
implementation
uses
MyAssertions, MyUtils, MyTypes, MyMemory;
{ Format is saved in prefs files, so it must not change! }
const
lsize = 4;
magic_version = $12345678;
fixed_bit = 16;
tagged_bit = 0;
safeget_bit = 1;
type
header = record
version: longint;
size: longint;
cnt: indexType;
flags: longint;
space: longint;
end;
headerPtr = ^header;
headerHandle = ^headerPtr;
{ Data format: }
{ header}
{ [tag (lsize)] [length (lsize)] data }
function LongAtPtr (p: univ longintPtr): longint;
{$IFC not GENERATINGPOWERPC}
inline
$205F, $224F, $12D8, $12D8, $12D8, $12D8;
{ move.l (sp)+,a0 move.l sp,a1, 4*move.b (a0)+,(a1)+ }
{$ELSEC}
begin
LongAtPtr:=p^;
end;
{$ENDC}
function TagAtPtr (p: univ LongIntPtr): tagType;
{$IFC not GENERATINGPOWERPC}
inline
$205F, $224F, $12D8, $12D8, $12D8, $12D8;
{ move.l (sp)+,a0 move.l sp,a1, 4*move.b (a0)+,(a1)+ }
{$ELSEC}
begin
TagAtPtr:=tagType(p^);
end;
{$ENDC}
function EqualTag(t1, t2: OSType): Boolean;
begin
EqualTag := longint(t1) = longint(t2);
end;
procedure HackUpdateHandleToCollection (data: handle);
var
h: header;
pos: longint;
size: longint;
begin
if (GetHandleSize(data) < SizeOf(header)) | (headerHandle(data)^^.version <> magic_version) then begin
h.version := magic_version;
h.size := -1;
h.flags := 0;
BSET(h.flags, tagged_bit);
BSET(h.flags, safeget_bit);
h.space := 0;
h.cnt := 0;
pos := 0;
while (pos >= 0) & (pos <= GetHandleSize(data) - 8) do begin
h.cnt := h.cnt + 1;
size := LongAtPtr(ptr(ord(data^) + lsize));
if (size < 0) | (size > 1000) then begin
pos := -1;
end else begin
pos := pos + 8 + size;
end;
end;
if pos <> GetHandleSize(data) then begin
SetHandleSize(data, 0);
h.cnt := 0;
end;
pos := Munger(data, 0, nil, 0, @h, SizeOf(h));
end;
end;
procedure collection.Create (siz: longint; fix, tag: boolean);
begin
HLock(handle(self));
data := NewHandle(SizeOf(header));
size := siz;
fixed := fix;
tagged := tag;
safeget := false;
testheap := false;
lensize := lsize * ord(not fixed);
tagsize := lsize * ord(tagged);
Reset;
end;
procedure collection.Destroy;
begin
DisposeHandle(data);
dispose(self);
end;
function collection.GetDataHandle: handle;
var
flags: longint;
begin
headerHandle(data)^^.version := magic_version;
headerHandle(data)^^.size := size;
headerHandle(data)^^.cnt := cnt;
flags := 0;
if fixed then begin
BSET(flags, fixed_bit);
end;
if tagged then begin
BSET(flags, tagged_bit);
end;
if safeget then begin
BSET(flags, safeget_bit);
end;
headerHandle(data)^^.flags := flags;
headerHandle(data)^^.space := 0;
GetDataHandle := data;
end;
procedure collection.SetDataHandle (d: handle);
var
flags: longint;
begin
if headerHandle(d)^^.version = magic_version then begin
DisposeHandle(data);
data := d;
error := noErr;
size := headerHandle(data)^^.size;
cnt := headerHandle(data)^^.cnt;
flags := headerHandle(data)^^.flags;
fixed := BTST(flags, fixed_bit);
tagged := BTST(flags, tagged_bit);
safeget := BTST(flags, safeget_bit);
testheap := false;
lensize := lsize * ord(not fixed);
tagsize := lsize * ord(tagged);
InvalidateCache;
end
else begin
Reset;
error := -1;
end;
end;
procedure collection.CreateFromHandle (d: handle);
begin
data := NewHandle(SizeOf(header));
SetDataHandle(d);
end;
procedure collection.Reset;
begin
error := noErr;
cnt := 0;
SetHandleSize(data, SizeOf(header));
InvalidateCache;
end;
procedure collection.InvalidateCache;
begin
cacheoffset := -1;
end;
procedure collection.Permute (map: PermuteArrayPtr);
type
LongArray = array[1..8000] of longint;
LongArrayPtr = ^LongArray;
var
i, j, k: integer;
offset, src, len, handlesize, result: longint;
dummy: boolean;
newdata: handle;
offsetptr: LongArrayPtr;
err: OSErr;
begin
handlesize := GetHandleSize(data);
newdata := TempNewHandle(handlesize, err);
if newdata = nil then begin
newdata := NewHandle(handlesize);
end;
offsetptr := nil;
if newdata <> nil then begin
err := MNewPtr(offsetptr, longint(cnt) * 4);
end;
if offsetptr <> nil then begin
offset := SizeOf(header) + tagsize;
for i := 1 to cnt do begin
offsetptr^[i] := offset - tagsize;
if fixed then begin
offset := offset + size + tagsize;
end
else begin
offset := offset + lsize + LongAtPtr(ptr(ord(data^) + offset)) + tagsize; { point to next length }
end;
end;
offset := SizeOf(header);
len := size + tagsize + lensize;
for i := 1 to cnt do begin
src := offsetptr^[map^[i]];
if not fixed then begin
len := tagsize + LongAtPtr(ptr(ord(data^) + src + tagsize)) + lensize;
end;
BlockMoveData(ptr(ord(data^) + src), ptr(ord(newdata^) + offset), len);
offset := offset + len;
end;
Assert(offset = handlesize);
BlockMoveData(newdata^, data^, handlesize);
MDisposePtr(offsetptr);
DisposeHandle(newdata);
end else begin
DisposeHandle(newdata); { nil safe }
for i := 1 to cnt do begin
k := map^[i];
cacheoffset := -1;
dummy := GetOffset(k, offset, len);
Assert(dummy);
offset := offset - tagsize - lensize;
len := len + tagsize + lensize;
SetHandleSize(data, handlesize + len);
Assert(MemError = noErr);
HLock(data);
BlockMoveData(ptr(ord(data^) + offset), ptr(ord(data^) + handlesize), len);
HUnlock(data);
result := Munger(data, offset, nil, len, @data, 0);
cacheoffset := -1;
for j := 1 to cnt do begin
if map^[j] > k then begin
map^[j] := map^[j] - 1;
end;
end;
end;
end;
InvalidateCache;
end;
function collection.GetOffset (index: indexType; var offset: longint; var len: longint): boolean; { PRIVATE }
var
valid: boolean;
i: indexType;
begin
if testheap then begin
DebugStr('GetOffset;hc;g');
end;
valid := (0 < index) & (index <= cnt);
if valid then begin
if fixed then begin
len := size;
offset := SizeOf(header) + (index - 1) * (size + tagsize) + tagsize;
end
else begin
if (cacheoffset > 0) & (searchindex > 0) & (searchindex <= index) then begin
offset := cacheoffset - lsize;
i := searchindex;
end
else begin
offset := SizeOf(header) + tagsize; { point to first length }
i := 1;
end;
while (i < index) do begin
offset := offset + lsize + LongAtPtr(ptr(ord(data^) + offset)) + tagsize; { point to next length }
i := i + 1;
end;
len := LongAtPtr(ptr(ord(data^) + offset));
offset := offset + lsize; { point to data }
end;
cacheoffset := offset;
cachelen := len;
searchindex := index;
end
else begin
Assert(false);
InvalidateCache;
end;
GetOffset := valid;
end;
function collection.GetTagOffset (tag: univ tagType; var offset: longint; var len: longint; var index: indexType; test: boolean): boolean; { PRIVATE }
var
valid: boolean;
t: tagType;
handlesize: longint;
begin
if testheap then begin
DebugStr('GetTagOffset;hc;g');
end;
valid := false;
if tagged then begin
if (cacheoffset > 0) & (searchindex < 0) & EqualTag(searchtag, tag) then begin
offset := cacheoffset;
len := cachelen;
index := cacheindex;
valid := true;
end
else begin
len := size;
index := 0;
offset := SizeOf(header); { point to first tag }
handlesize := GetHandleSize(data);
while (not valid) & (index < cnt) do begin
Assert((0 < offset) & (offset < handlesize));
t := TagAtPtr(ptr(ord(data^) + offset));
if not fixed then begin
len := LongAtPtr(ptr(ord(data^) + offset + tagsize));
end;
offset := offset + tagsize + lensize + len; { point to next tag }
index := index + 1;
valid := EqualTag(t, tag);
end;
offset := offset - len; { point to data }
end;
end;
if not test then begin
Assert(valid);
end;
if valid then begin
cacheoffset := offset;
cachelen := len;
cacheindex := index;
searchindex := -1;
searchtag := tag;
end
else begin
InvalidateCache;
end;
GetTagOffset := valid;
end;
function collection.Count: indexType;
begin
Count := cnt;
end;
function collection.GetTag (index: indexType): tagType;
var
offset, len: longint;
begin
GetTag := tagType(no_tag);
Assert(tagged);
if GetOffset(index, offset, len) then begin
GetTag := TagAtPtr(ptr(ord(data^) + offset - lensize - tagsize));
end;
end;
procedure collection.SetTag (index: indexType; tag: tagType);
var
offset, len: longint;
begin
Assert(tagged);
if GetOffset(index, offset, len) then begin
BlockMoveData(@tag, ptr(ord(data^) + offset - lensize - tagsize), tagsize);
end;
end;
function collection.GetIndex (tag: tagType): indexType;
var
offset, len: longint;
index: indexType;
begin
GetIndex := 0;
if GetTagOffset(tag, offset, len, index, true) then begin
GetIndex := index;
end;
end;
function collection.Info (index: indexType; var len: longint): boolean;
var
offset: longint;
begin
Info := (1 <= index) & (index <= cnt) & GetOffset(index, offset, len);
end;
function collection.InfoTag (tag: univ tagType; var len: longint): boolean;
var
offset: longint;
index: indexType;
begin
{ DebugStr(concat('InfoTag ',NumToStr(longint(tag)),';g'));}
InfoTag := GetTagOffset(tag, offset, len, index, true);
end;
function collection.Exists (index: indexType): boolean;
var
len: longint;
begin
Exists := Info(index, len);
end;
function collection.ExistsTag (tag: univ tagType): boolean;
var
len: longint;
begin
ExistsTag := InfoTag(tag, len);
end;
procedure collection.Delete (index: indexType);
var
offset, len: longint;
begin
if GetOffset(index, offset, len) then begin
offset := Munger(data, offset - tagsize - lensize, nil, tagsize + lensize + len, @offset, 0);
cnt := cnt - 1;
InvalidateCache;
end;
end;
procedure collection.DeleteTag (tag: univ tagType);
var
offset, len: longint;
index: indexType;
begin
if GetTagOffset(tag, offset, len, index, true) then begin
offset := Munger(data, offset - tagsize - lensize, nil, tagsize + lensize + len, @offset, 0);
cnt := cnt - 1;
InvalidateCache;
end;
end;
procedure collection.AddChunk (tag: tagType; p: ptr; len: longint);
var
orgsize: longint;
begin
if testheap then begin
DebugStr('AddChunk Enter;hc;g');
end;
if error = noErr then begin
orgsize := GetHandleSize(data);
SetHandleSize(data, orgsize + tagsize + lensize + len);
if MemError = noErr then begin
if tagged then begin
BlockMoveData(@tag, ptr(ord(data^) + orgsize), lsize);
orgsize := orgsize + lsize;
end
else begin
Assert(EqualTag(tag, tagType(no_tag)));
end;
if not fixed then begin
BlockMoveData(@len, ptr(ord(data^) + orgsize), lsize);
orgsize := orgsize + lsize;
end
else begin
Assert(len = size);
end;
BlockMoveData(p, ptr(ord(data^) + orgsize), len);
cnt := cnt + 1;
end;
end;
if testheap then begin
DebugStr('AddChunk Exit;hc;g');
end;
end;
procedure collection.InsertBefore (index: indexType);
var
offset, len, oe: longint;
t: tagType;
begin
t := tagType(no_tag);
if index = Count + 1 then begin
if fixed then begin
AddChunk(t, @index, size);
end
else begin
AddChunk(t, @index, 0);
end;
end
else begin
if GetOffset(index, offset, len) then begin
offset := offset - lensize - tagsize;
if tagged then begin
oe := Munger(data, offset, nil, 0, @t, tagsize);
offset := offset + tagsize;
end;
if fixed then begin
oe := Munger(data, offset, nil, 0, @index, size);
end
else begin
len := 0;
oe := Munger(data, offset, nil, 0, @len, lensize);
end;
if error = noErr then begin
error := MemError;
end;
cnt := cnt + 1;
InvalidateCache;
end;
end;
end;
procedure collection.SetChunk (offset, l: longint; tag: tagType; p: ptr; len: longint);
begin
if tagged then begin
BlockMoveData(@tag, ptr(ord(data^) + offset - lensize - tagsize), tagsize);
end
else begin
Assert(EqualTag(tag, tagType(no_tag)));
end;
if fixed then begin
Assert(len = size);
end;
if l = len then begin
BlockMoveData(p, ptr(ord(data^) + offset), len);
end
else begin
BlockMoveData(@len, ptr(ord(data^) + offset - lensize), lensize);
offset := Munger(data, offset, nil, l, p, len);
if error = noErr then begin
error := MemError;
end;
end;
InvalidateCache;
end;
procedure collection.SetChunkIndex (index: indexType; p: ptr; len: longint);
var
offset, l: longint;
begin
if GetOffset(index, offset, l) then begin
SetChunk(offset, l, tagType(no_tag), p, len);
end;
end;
procedure collection.SetChunkTag (tag: tagType; p: ptr; len: longint);
var
offset, l: longint;
index: indexType;
begin
if GetTagOffset(tag, offset, l, index, true) then begin
SetChunk(offset, l, tag, p, len);
end
else begin
AddChunk(tag, p, len);
end;
end;
procedure collection.GetChunkIndex (index: indexType; len: longint; p: ptr);
var
offset, l: longint;
begin
if GetOffset(index, offset, l) then begin
Assert(l = len);
BlockMoveData(ptr(ord(data^) + offset), p, len);
end;
end;
procedure collection.GetChunkTag (tag: tagType; len: longint; p: ptr);
var
offset, l: longint;
index: indexType;
begin
if GetTagOffset(tag, offset, l, index, safeget) then begin
Assert(l = len);
BlockMoveData(ptr(ord(data^) + offset), p, len);
end
else begin
MZero(p, len);
end;
end;
procedure collection.AddBoolean (b: boolean);
var
n: integer;
begin
n := -ord(b);
AddChunk(tagType(no_tag), @n, 1);
end;
procedure collection.AddTagBoolean (tag: univ tagType; b: boolean);
var
n: integer;
begin
n := -ord(b);
AddChunk(tag, @n, 1);
end;
procedure collection.AddLong (n: univ longint);
begin
AddChunk(tagType(no_tag), @n, lsize);
end;
procedure collection.AddTagLong (tag: univ tagType; n: univ longint);
begin
AddChunk(tag, @n, lsize);
end;
procedure collection.AddString (s: Str255);
begin
AddChunk(tagType(no_tag), @s[1], length(s));
end;
procedure collection.AddTagString (tag: univ tagType; s: Str255);
begin
AddChunk(tag, @s[1], length(s));
end;
procedure collection.AddData (p: ptr; len: longint);
begin
AddChunk(tagType(no_tag), p, len);
end;
procedure collection.AddTagData (tag: univ tagType; p: ptr; len: longint);
begin
AddChunk(tag, p, len);
end;
procedure collection.AddItem (p: ptr);
begin
AddChunk(tagType(no_tag), p, size);
end;
procedure collection.AddTagItem (tag: univ tagType; p: ptr);
begin
AddChunk(tag, p, size);
end;
procedure collection.SetBoolean (index: indexType; b: boolean);
var
n: integer;
begin
n := -ord(b);
SetChunkIndex(index, @n, 1);
end;
procedure collection.SetTagBoolean (tag: univ tagType; b: boolean);
var
n: integer;
begin
n := -ord(b);
SetChunkTag(tag, @n, 1);
end;
procedure collection.SetLong (index: indexType; n: univ longint);
begin
SetChunkIndex(index, @n, lsize);
end;
procedure collection.SetTagLong (tag: univ tagType; n: univ longint);
begin
SetChunkTag(tag, @n, lsize);
end;
procedure collection.SetString (index: indexType; s: Str255);
begin
SetChunkIndex(index, @s[1], length(s));
end;
procedure collection.SetTagString (tag: univ tagType; s: Str255);
begin
SetChunkTag(tag, @s[1], length(s));
end;
procedure collection.SetData (index: indexType; p: ptr; len: longint);
begin
SetChunkIndex(index, p, len);
end;
procedure collection.SetTagData (tag: univ tagType; p: ptr; len: longint);
begin
SetChunkTag(tag, p, len);
end;
procedure collection.SetItem (index: indexType; p: ptr);
begin
SetChunkIndex(index, p, size);
end;
procedure collection.SetTagItem (tag: univ tagType; p: ptr);
begin
SetChunkTag(tag, p, size);
end;
function collection.GetBoolean (index: indexType): boolean;
var
n: integer;
begin
n := 0;
GetChunkIndex(index, 1, @n);
GetBoolean := n <> 0;
end;
function collection.GetTagBoolean (tag: univ tagType): boolean;
var
n: integer;
begin
n := 0;
GetChunkTag(tag, 1, @n);
GetTagBoolean := n <> 0;
end;
procedure collection.GetLong (index: indexType; var l: univ longint);
begin
GetChunkIndex(index, 4, @l);
end;
procedure collection.GetTagLong (tag: univ tagType; var l: univ longint);
begin
GetChunkTag(tag, 4, @l);
end;
function collection.GetString (index: indexType): Str255;
var
offset, l: longint;
s: Str255;
begin
s := '';
if GetOffset(index, offset, l) then begin
Assert(l <= 255);
BlockMoveData(ptr(ord(data^) + offset), @s[1], l);
s[0] := chr(l);
end;
GetString := s;
end;
function collection.GetTagString (tag: univ tagType): Str255;
var
offset, l: longint;
index: indexType;
s: Str255;
begin
s := '';
if GetTagOffset(tag, offset, l, index, safeget) then begin
Assert(l <= 255);
BlockMoveData(ptr(ord(data^) + offset), @s[1], l);
s[0] := chr(l);
end;
GetTagString := s;
end;
procedure collection.GetData (index: indexType; p: ptr; len: longint);
begin
GetChunkIndex(index, len, p);
end;
procedure collection.GetTagData (tag: univ tagType; p: ptr; len: longint);
begin
GetChunkTag(tag, len, p);
end;
procedure collection.GetItem (index: indexType; p: ptr);
begin
GetChunkIndex(index, size, p);
end;
procedure collection.GetTagItem (tag: univ tagType; p: ptr);
begin
GetChunkTag(tag, size, p);
end;
end.